package cn.edu.nit.sys.service.impl;

import cn.edu.nit.sys.entity.Menu;
import cn.edu.nit.sys.entity.Role;
import cn.edu.nit.sys.entity.RoleMenu;
import cn.edu.nit.sys.mapper.MenuMapper;
import cn.edu.nit.sys.mapper.RoleMapper;
import cn.edu.nit.sys.service.MenuService;
import cn.edu.nit.sys.service.RoleService;
import cn.edu.nit.sys.utils.R;
import cn.edu.nit.sys.vo.MenuVO;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @Author xiaobai
 * @Date 2022/8/24 22:05
 * @Version 1.0.0
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Autowired
    private RoleMapper roleMapper;

    @Override
    public R getMenus(String uid) {
        List<Menu> routes = baseMapper.getRoutes(uid);
        menuFormat(routes);
        return R.ok(menuFormat(routes));
    }

    @Override
    public R getMenuList(Page<Menu> page, String name) {
        Page<Menu> getMenuList = baseMapper.getMenuList(page, name);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("total", getMenuList.getTotal());
        jsonObject.put("list", menuFormat(getMenuList.getRecords()));
        return R.ok(jsonObject);
    }

    @Override
    public R getAll() {
        List<Menu> all = baseMapper.getAll();
        return R.ok(menuFormat(all));
    }

    @Override
    @Transactional
    public R addMenu(MenuVO menuVO) {
        List<String> roleList = null;
        Integer rs = null;
        try {
            QueryWrapper<Menu> wrapper = new QueryWrapper<>();
            wrapper.eq("name", menuVO.getName())
                    .eq("label", menuVO.getLabel());
            Menu selectOne = baseMapper.selectOne(wrapper);
            if (ObjectUtils.isNotEmpty(selectOne)) {
                return R.error("菜单已存在");
            }
            roleList = menuVO.getRoles();
            Menu menu = new Menu();
            BeanUtils.copyProperties(menuVO, menu);
            if(StringUtils.isEmpty(menuVO.getParent())) {
                menu.setParent(0);
            }else {
                menu.setParent(Integer.parseInt(menuVO.getParent()));
            }
            int menuId = baseMapper.addMenu(menu);
            rs = 0;
            if(menuId > 0) {
                for (int i = 0; i < roleList.size(); i++) {
                    QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("role", roleList.get(i));
                    Role role = roleMapper.selectOne(queryWrapper);
                    rs += baseMapper.addRoleMenu(menu.getId(), role.getId());
                }
            }
        } catch (BeansException e) {
            throw new RuntimeException("添加失败，事物回滚");
        }
        return rs == roleList.size() ? R.ok("添加成功") : R.error("添加失败");
    }

    @Override
    @Transactional
    public boolean updateMenu(MenuVO menuVO) {
        Integer integer = 0;
        try {
            integer = baseMapper.updateMenu(menuVO);
            List<RoleMenu> roleMenuList = baseMapper.selectAllRoleMenu(menuVO.getId()); // 获取当前菜单对应所有角色
            if(ObjectUtils.isNotEmpty(roleMenuList) && ObjectUtils.isNotEmpty(menuVO.getRoles())) {
                List<Integer> ids = new ArrayList<>();
                for(int i = 0; i < roleMenuList.size(); i++){
                    for (int j = 0; j < menuVO.getRoles().size(); j++) {
                        QueryWrapper<Role> wrapper = new QueryWrapper<>();
                        wrapper.eq("role", menuVO.getRoles().get(j));
                        Role role = roleMapper.selectOne(wrapper);
                        RoleMenu roleMenu = baseMapper.selectRoleMenuByRoleAndMenu(role.getId(), menuVO.getId());
                        if (ObjectUtils.isEmpty(roleMenu)) {
                            // 此角色未此菜单操作权限 ==> 插入记录
                            integer += baseMapper.addRoleMenu(menuVO.getId(), role.getId());
                            ids.add(role.getId());
                        }else {
                            ids.add(roleMenu.getRoleId());
                        }
                    }
                }
                integer += baseMapper.delRoleMenu(ids, menuVO.getId());
            }else if (ObjectUtils.isEmpty(roleMenuList)) {
                for (int j = 0; j < menuVO.getRoles().size(); j++) {
                    QueryWrapper<Role> wrapper = new QueryWrapper<>();
                    wrapper.eq("role", menuVO.getRoles().get(j));
                    Role role = roleMapper.selectOne(wrapper);
                    // 此角色未此菜单操作权限 ==> 插入记录
                    integer += baseMapper.addRoleMenu(menuVO.getId(), role.getId());
                }
            }else if(ObjectUtils.isEmpty(menuVO.getRoles())) {
                integer += baseMapper.delAllRoleMenuByMenuId(menuVO.getId());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("修改失败，事物回滚");
        }
        return integer > 0;
    }

    @Override
    public R delMenu(Integer id) {
        return baseMapper.delMenu(id) > 0 ? R.ok("删除成功") : R.error("删除失败");
    }

    @Override
    public boolean lockMenu(Integer id) {
        Menu menu = baseMapper.selectById(id);
        Integer disabled = menu.getDisabled() > 0 ? 0 : 1;
        return baseMapper.lockMenu(id, disabled);
    }

    /**
     * 菜单格式化
     * @param menuList
     * @return
     */
    private List<Menu> menuFormat(List<Menu> menuList) {
        List<Menu> menus = new ArrayList<>();
        for (int i = 0; i < menuList.size(); i++) {
            Menu parent = menuList.get(i);
            List<Menu> childrenList = new ArrayList<>();
            for (int j = 0; j < menuList.size(); j++) {
                Menu children = menuList.get(j);
                if(parent.getId() == children.getParent() && parent.getId() != children.getId()) {
                    childrenList.add(children);
                }
            }
            // 子菜单排序
            if(childrenList.size() > 1){
                childrenList.sort((Menu o1, Menu o2) -> (o1.getSort() - o2.getSort()));
            }
            if(parent.getParent() == 0) {
                parent.setChildren(childrenList);
                menus.add(parent);
            }
            // 一级菜单排序
            if(menus.size() > 1) {
                menus.sort((Menu o1, Menu o2) -> (o1.getSort() - o2.getSort()));
            }
        }
        return menus;
    }
}
